
// -----------------------------------------------------------------------------

#include "stdafx.h"
#include "Win32.Security.Cryptography.Providers.h"

// -----------------------------------------------------------------------------

namespace Kif
{
namespace Win32
{
namespace Security
{
namespace Cryptography
{

#define NT_SUCCESS(Status)  (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)

// -----------------------------------------------------------------------------

/// <summary>Get Algorithm Id</summary>
/// <returns>The Algorithm Id is returned, else NULL</returns>
wchar_t *Provider::GetAlgorithmId(CryptAlgorithm algorithm)
{
   wchar_t *aid = NULL;
   switch(algorithm)
   {
      // The triple data encryption standard symmetric encryption algorithm.
      // Standard: FIPS 46-3, FIPS 81, SP800-38A
      case CryptAlgorithm_TripleDES:
         aid = BCRYPT_3DES_ALGORITHM;
         break;

      // The 112-bit triple data encryption standard symmetric encryption
      // algorithm. Standard: FIPS 46-3, FIPS 81, SP800-38A
      case CryptAlgorithm_TripleDES_112:
         aid = BCRYPT_3DES_112_ALGORITHM;
         break;

      // The advanced encryption standard symmetric encryption algorithm.
      // Standard: FIPS 197
      case CryptAlgorithm_AES:
         aid = BCRYPT_AES_ALGORITHM;
         break;

      // The advanced encryption standard (AES) Galois message authentication
      // code (GMAC) symmetric encryption algorithm.
      // Standard: SP800-38D
      //case CryptAlgorithm_AES_GMAC:
      //   aid = BCRYPT_AES_GMAC_ALGORITHM;
      //   break;

      // The data encryption standard symmetric encryption algorithm.
      // Standard: FIPS 46-3, FIPS 81
      case CryptAlgorithm_DES:
         aid = BCRYPT_DES_ALGORITHM;
         break;

      // The extended data encryption standard symmetric encryption algorithm.
      // Standard: None
      case CryptAlgorithm_DESX:
         aid = BCRYPT_DESX_ALGORITHM;
         break;

      // The Diffie-Hellman key exchange algorithm.
      // Standard: PKCS #3
      case CryptAlgorithm_DH:
         aid = BCRYPT_DH_ALGORITHM;
         break;

      // The digital signature algorithm.
      // Standard: FIPS 186-2
      case CryptAlgorithm_DSA:
         aid = BCRYPT_DSA_ALGORITHM;
         break;

      // The 256-bit prime elliptic curve Diffie-Hellman key exchange algorithm.
      // Standard: SP800-56A
      case CryptAlgorithm_ECDH_P256:
         aid = BCRYPT_ECDH_P256_ALGORITHM;
         break;

      // The 384-bit prime elliptic curve Diffie-Hellman key exchange algorithm.
      // Standard: SP800-56A
      case CryptAlgorithm_ECDH_P384:
         aid = BCRYPT_ECDH_P384_ALGORITHM;
         break;

      // The 521-bit prime elliptic curve Diffie-Hellman key exchange algorithm.
      // Standard: SP800-56A
      case CryptAlgorithm_ECDH_P521:
         aid = BCRYPT_ECDH_P521_ALGORITHM;
         break;

      // The 256-bit prime elliptic curve digital signature algorithm
      // (FIPS 186-2).  Standard: FIPS 186-2, X9.62
      case CryptAlgorithm_ECDSA_P256:
         aid = BCRYPT_ECDSA_P256_ALGORITHM;
         break;

      // The 384-bit prime elliptic curve digital signature algorithm
      // (FIPS 186-2). Standard: FIPS 186-2, X9.62
      case CryptAlgorithm_ECDSA_P384:
         aid = BCRYPT_ECDSA_P384_ALGORITHM;
         break;

      // The 521-bit prime elliptic curve digital signature algorithm
      // (FIPS 186-2). Standard: FIPS 186-2, X9.62
      case CryptAlgorithm_ECDSA_P521:
         aid = BCRYPT_ECDSA_P521_ALGORITHM;
         break;

      // The MD2 hash algorithm.
      // Standard: RFC 1319
      case CryptAlgorithm_MD2:
         aid = BCRYPT_ECDSA_P521_ALGORITHM;
         break;

      // The MD4 hash algorithm.
      // Standard: RFC 1320
      case CryptAlgorithm_MD4:
         aid = BCRYPT_MD4_ALGORITHM;
         break;

      // The MD5 hash algorithm.
      // Standard: RFC 1321
      case CryptAlgorithm_MD5:
         aid = BCRYPT_MD5_ALGORITHM;
         break;

      // The RC2 block symmetric encryption algorithm.
      // Standard: RFC 2268
      case CryptAlgorithm_RC2:
         aid = BCRYPT_MD5_ALGORITHM;
         break;

      // The RC4 symmetric encryption algorithm.
      // Standard: Various
      case CryptAlgorithm_RC4:
         aid = BCRYPT_MD5_ALGORITHM;
         break;

      // The random-number generator algorithm.
      // Standard: FIPS 186-2, FIPS 140-2
      case CryptAlgorithm_RNG:
         aid = BCRYPT_RNG_ALGORITHM;
         break;

      // The dual elliptical curve random-number generator algorithm.
      // Standard: SP800-90
      //case CryptAlgorithm_RNG_DUAL_EC:
      //   aid = BCRYPT_RNG_DUAL_EC_ALGORITHM;
      //   break;

      // The random-number generator algorithm suitable for DSA
      // (Digital Signature Algorithm). Standard: FIPS 186-2
      case CryptAlgorithm_RNG_FIPS186_DSA:
         aid = BCRYPT_RNG_FIPS186_DSA_ALGORITHM;
         break;

      // The RSA public key algorithm.
      // Standard: PKCS#1 v1.5 and v2.0.
      case CryptAlgorithm_RSA:
         aid = BCRYPT_RSA_ALGORITHM;
         break;

      // The RSA signature algorithm. This algorithm is not currently supported. You can use the BCRYPT_RSA_ALGORITHM algorithm to perform RSA signing operations.
      // Standard: PKCS#1 v1.5 and v2.0.
      case CryptAlgorithm_RSA_SIGN:
         aid = BCRYPT_RSA_SIGN_ALGORITHM;
         break;

      // The 160-bit secure hash algorithm.
      // Standard: FIPS 180-2, FIPS 198
      case CryptAlgorithm_SHA1:
         aid = BCRYPT_SHA1_ALGORITHM;
         break;

      // The 256-bit secure hash algorithm.
      // Standard: FIPS 180-2, FIPS 198
      case CryptAlgorithm_SHA256:
         aid = BCRYPT_SHA256_ALGORITHM;
         break;

      // The 384-bit secure hash algorithm.
      // Standard: FIPS 180-2, FIPS 198
      case CryptAlgorithm_SHA384:
         aid = BCRYPT_SHA384_ALGORITHM;
         break;

      // The 512-bit secure hash algorithm.
      // Standard: FIPS 180-2, FIPS 198
      case CryptAlgorithm_SHA512:
         aid = BCRYPT_SHA512_ALGORITHM;
         break;

      default:
         aid = NULL;
         break;
   }
   return aid;
}  // end of GetAlgorithmId

/// <summary>Open Algorithm Provider</summary>
/// <returns>true is returned if succeded to open algorithm provider</returns>
bool Provider::OpenAlgorithmProvider(CryptAlgorithm algorithm)
{
   LastReturnedStatus = STATUS_UNSUCCESSFUL;
   Dispose();

   //open an algorithm handle
   wchar_t *algorithmId = GetAlgorithmId(algorithm);
   if (algorithmId == NULL)
      return false;

   LastReturnedStatus = BCryptOpenAlgorithmProvider(
      &hAlgorithmHandle, algorithmId, NULL, 0);

   return NT_SUCCESS(LastReturnedStatus);
}  // end of Provider

/// <summary>Initialize provider (ctor)</summary>
Provider::Provider()
{
   hAlgorithmHandle = NULL;
}  // end of Provider

/// <summary>Initialize provider (ctor)</summary>
/// <param name="algorithm">Algorithm to get provider for...</param>
Provider::Provider(CryptAlgorithm algorithm)
{
   hAlgorithmHandle = NULL;
   OpenAlgorithmProvider(algorithm);
}  // end of Provider

/// <summary>Release allocated resources</summary>
void Provider::Dispose()
{
   if (hAlgorithmHandle != NULL)
   {
      BCryptCloseAlgorithmProvider(hAlgorithmHandle,0);
   }
   hAlgorithmHandle = NULL;
}  // end of Dispose

/// <summary>Release allocated resources for provider (dtor)</summary>
Provider::~Provider()
{
   Dispose();
}  // end of ~Provider (dtor)

// -----------------------------------------------------------------------------

}  // end of Kif::Win32::Security::Cryptography
}  // end of Kif::Win32::Security
}  // end of Kif::Win32
}  // end of Kif

